home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1 / win / tty / wintty.c < prev   
Encoding:
C/C++ Source or Header  |  1993-01-23  |  35.9 KB  |  1,583 lines

  1. /*    SCCS Id: @(#)wintty.c    3.1    92/10/21    */
  2. /* Copyright (c) David Cohrs, 1991                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6. #include "termcap.h"
  7. #include "wintty.h"
  8. #if (defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE)) && defined(CLIPPING)
  9. #include <signal.h>
  10. #endif
  11.  
  12. #define DEBUG
  13.  
  14. extern const char *roles[];    /* from u_init.c */
  15.  
  16. /* Interface definition, for windows.c */
  17. struct window_procs tty_procs = {
  18.     "tty",
  19.     tty_init_nhwindows,
  20.     tty_player_selection,
  21.     tty_askname,
  22.     tty_get_nh_event,
  23.     tty_exit_nhwindows,
  24.     tty_suspend_nhwindows,
  25.     tty_resume_nhwindows,
  26.     tty_create_nhwindow,
  27.     tty_clear_nhwindow,
  28.     tty_display_nhwindow,
  29.     tty_destroy_nhwindow,
  30.     tty_curs,
  31.     tty_putstr,
  32.     tty_display_file,
  33.     tty_start_menu,
  34.     tty_add_menu,
  35.     tty_end_menu,
  36.     tty_select_menu,
  37.     tty_update_inventory,
  38.     tty_mark_synch,
  39.     tty_wait_synch,
  40. #ifdef CLIPPING
  41.     tty_cliparound,
  42. #endif
  43.     tty_print_glyph,
  44.     tty_raw_print,
  45.     tty_raw_print_bold,
  46.     tty_nhgetch,
  47.     tty_nh_poskey,
  48.     tty_nhbell,
  49.     tty_doprev_message,
  50.     tty_yn_function,
  51.     tty_getlin,
  52. #ifdef COM_COMPL
  53.     tty_get_ext_cmd,
  54. #endif /* COM_COMPL */
  55.     tty_number_pad,
  56.     tty_delay_output,
  57.     /* other defs that really should go away (they're tty specific) */
  58.     tty_start_screen,
  59.     tty_end_screen,
  60. };
  61.  
  62. static int maxwin = 0;            /* number of windows in use */
  63. winid BASE_WINDOW;
  64. struct WinDesc *wins[MAXWIN];
  65. struct DisplayDesc *ttyDisplay;    /* the tty display descriptor */
  66.  
  67. extern void FDECL(cmov, (int,int)); /* from termcap.c */
  68. extern void FDECL(nocmov, (int,int)); /* from termcap.c */
  69. #if defined(UNIX) || defined(VMS)
  70. static char obuf[BUFSIZ];    /* BUFSIZ is defined in stdio.h */
  71. #endif
  72.  
  73. static char winpanicstr[] = "Bad window id %d";
  74. char defmorestr[] = "--More--";
  75.  
  76. #ifdef CLIPPING
  77. static boolean clipping = FALSE;    /* clipping on? */
  78. static int clipx = 0, clipy = 0, clipxmax = 0, clipymax = 0;
  79. #endif
  80.  
  81. #ifdef ASCIIGRAPH
  82. boolean GFlag = FALSE;
  83. #endif
  84.  
  85. #ifdef MICRO
  86. #define getret() getreturn("to continue")
  87. #else
  88. static void NDECL(getret);
  89. #endif
  90. static void FDECL(dmore,(struct WinDesc *));
  91. static char * FDECL(s_atr2str, (int));
  92. static char * FDECL(e_atr2str, (int));
  93. static const char * FDECL(compress_str, (const char *));
  94. static void FDECL(tty_putsym, (winid, int, int, CHAR_P));
  95.  
  96. #if defined(SIGWINCH) && defined(CLIPPING)
  97. static void
  98. winch()
  99. {
  100.     int oldLI = LI, oldCO = CO, i;
  101.     register struct WinDesc *cw;
  102.  
  103.     getwindowsz();
  104.     if((oldLI != LI || oldCO != CO) && ttyDisplay) {
  105.     ttyDisplay->rows = LI;
  106.     ttyDisplay->cols = CO;
  107.  
  108.     cw = wins[BASE_WINDOW];
  109.     cw->rows = ttyDisplay->rows;
  110.     cw->cols = ttyDisplay->cols;
  111.  
  112.     if(flags.window_inited) {
  113.         cw = wins[WIN_MESSAGE];
  114.         cw->curx = cw->cury = 0;
  115.  
  116.         tty_destroy_nhwindow(WIN_STATUS);
  117.         WIN_STATUS = tty_create_nhwindow(NHW_STATUS);
  118.  
  119.         if(u.ux) {
  120. #ifdef CLIPPING
  121.         if(CO < COLNO || LI < ROWNO+3) {
  122.             setclipped();
  123.             tty_cliparound(u.ux, u.uy);
  124.         } else {
  125.             clipping = FALSE;
  126.             clipx = clipy = 0;
  127.         }
  128. #endif
  129.         i = ttyDisplay->toplin;
  130.         ttyDisplay->toplin = 0;
  131.         docrt();
  132.         bot();
  133.         ttyDisplay->toplin = i;
  134.         flush_screen(1);
  135.         if(i) {
  136.             addtopl(toplines);
  137.         } else
  138.             for(i=WIN_INVEN; i < MAXWIN; i++)
  139.             if(wins[i] && wins[i]->active) {
  140.                 /* cop-out */
  141.                 addtopl("Press Return to continue: ");
  142.                 break;
  143.             }
  144.         (void) fflush(stdout);
  145.         if(i < 2) flush_screen(1);
  146.         }
  147.     }
  148.     }
  149. }
  150. #endif
  151.  
  152. void
  153. tty_init_nhwindows()
  154. {
  155.     int wid, hgt;
  156.  
  157.     /*
  158.      *  Remember tty modes, to be restored on exit.
  159.      *
  160.      *  gettty() must be called before tty_startup()
  161.      *    due to ordering of LI/CO settings
  162.      *  tty_startup() must be called before initoptions()
  163.      *    due to ordering of graphics settings
  164.      */
  165. #if defined(UNIX) || defined(VMS)
  166.     setbuf(stdout,obuf);
  167. #endif
  168.     gettty();
  169.  
  170.     /* to port dependant tty setup */
  171.     tty_startup(&wid, &hgt);
  172.     setftty();            /* calls start_screen */
  173.  
  174.     /* set up tty descriptor */
  175.     ttyDisplay = (struct DisplayDesc*) alloc(sizeof(struct DisplayDesc));
  176.     ttyDisplay->toplin = 0;
  177.     ttyDisplay->rows = hgt;
  178.     ttyDisplay->cols = wid;
  179.     ttyDisplay->curx = ttyDisplay->cury = 0;
  180.     ttyDisplay->inmore = ttyDisplay->inread = 0;
  181. #ifdef TEXTCOLOR
  182.     ttyDisplay->color = NO_COLOR;
  183. #endif
  184.     ttyDisplay->attrs = 0;
  185.  
  186.     /* set up the default windows */
  187.     BASE_WINDOW = tty_create_nhwindow(NHW_BASE);
  188.     wins[BASE_WINDOW]->active = 1;
  189.  
  190.     ttyDisplay->lastwin = WIN_ERR;
  191.  
  192. #if defined(SIGWINCH) && defined(CLIPPING)
  193.     (void) signal(SIGWINCH, winch);
  194. #endif
  195.  
  196.     tty_clear_nhwindow(BASE_WINDOW);
  197.  
  198.     tty_putstr(BASE_WINDOW, 0, "");
  199.     tty_putstr(BASE_WINDOW, 0,
  200.      "NetHack, Copyright 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993");
  201.     tty_putstr(BASE_WINDOW, 0,
  202.      "         By Stichting Mathematisch Centrum and M. Stephenson.");
  203.     tty_putstr(BASE_WINDOW, 0, "         See license for details.");
  204.     tty_putstr(BASE_WINDOW, 0, "");
  205.     tty_display_nhwindow(BASE_WINDOW, FALSE);
  206. }
  207.  
  208. void
  209. tty_player_selection()
  210. {
  211.     char pbuf[QBUFSZ];
  212.     char pick, pc;
  213.     int i, linecount;
  214.  
  215.     linecount = wins[BASE_WINDOW]->cury+1;
  216.     if ((pc = highc(pl_character[0])) != 0) {
  217.     if(index(pl_classes, pc) != (char*) 0)
  218.         goto got_suffix;
  219.     tty_putstr(BASE_WINDOW, 0, "");
  220.     Sprintf(pbuf, "Unknown role: %c", pc);
  221.     tty_putstr(BASE_WINDOW, 0, pbuf);
  222.     linecount += 2;
  223.     pl_character[0] = pc = 0;
  224.     }
  225.  
  226. #define PICK_PROMPT "Shall I pick a character for you? [Y, N, or Q(quit)] "
  227.     tty_putstr(BASE_WINDOW, 0, "");
  228.     tty_putstr(BASE_WINDOW, 0, PICK_PROMPT);
  229.  
  230.     while(!index("yYnNqQ", (pick = readchar())) && !index(quitchars, pick))
  231.     tty_nhbell();
  232.  
  233.     pick = index(quitchars, pick) ? 'Y' : highc(pick);
  234.  
  235.     tty_putsym(BASE_WINDOW, (int)strlen(PICK_PROMPT)+1, linecount, pick); /* echo */
  236.  
  237.     if (pick == 'Q') {
  238.     clearlocks();
  239.     tty_exit_nhwindows(NULL);
  240.     terminate(0);
  241.     }
  242.  
  243.     if (pick == 'Y') {
  244.     tty_putstr(BASE_WINDOW, 0, "");
  245.     goto beginner;
  246.     }
  247.  
  248.     tty_curs(BASE_WINDOW, 1, linecount+2);
  249.     tty_putstr(BASE_WINDOW, 0, "What kind of character are you:");
  250.     tty_putstr(BASE_WINDOW, 0, "");
  251.     Sprintf(pbuf, "      %s,", An(roles[0]));
  252.     for(i = 1; roles[i]; i++) {
  253.     Sprintf(eos(pbuf), " %s", an(roles[i]));
  254.     if((((i + 1) % 4) == 0) && roles[i+1]) {
  255.         Strcat(pbuf, ",");
  256.         tty_putstr(BASE_WINDOW, 0, pbuf);
  257.         linecount++;
  258.         Strcpy(pbuf, "        ");
  259.     }
  260.     else if(roles[i+1] && roles[i+2])    Strcat(pbuf, ",");
  261.     if(roles[i+1] && !roles[i+2])    Strcat(pbuf, " or");
  262.     }
  263.     Strcat(pbuf ,"?");
  264.     tty_putstr(BASE_WINDOW, 0, pbuf);
  265.     Strcpy(pbuf, "         [");
  266.     for(i = 0; roles[i]; i++)
  267.     Sprintf(eos(pbuf), "%c,", pl_classes[i]);
  268.     Strcat(pbuf, " or Q] ");
  269.     tty_putstr(BASE_WINDOW, 0, pbuf);
  270.     linecount += 5;
  271.  
  272.     while ((pc = readchar()) != 0) {
  273.     if ((pc = highc(pc)) == 'Q') {
  274.         clearlocks();
  275.         tty_exit_nhwindows(NULL);
  276.         terminate(0);
  277.     }
  278.     if(index(pl_classes, pc) != (char *) 0) {
  279.         tty_putsym(BASE_WINDOW, (int)strlen(pbuf)+1, linecount, pc); /* echo */
  280.         tty_putstr(BASE_WINDOW, 0, "");
  281.         tty_display_nhwindow(BASE_WINDOW, TRUE);
  282.         break;
  283.     }
  284.     if(pc == '\n') {
  285.         pc = 0;
  286.         break;
  287.     }
  288.     tty_nhbell();
  289.     }
  290.  
  291. beginner:
  292.     if(!pc) {
  293.     i = rn2((int)strlen(pl_classes));
  294.     pc = pl_classes[i];
  295.     tty_putstr(BASE_WINDOW, 0, "");
  296.     Sprintf(pbuf, "This game you will be %s.", an(roles[i]));
  297.     tty_putstr(BASE_WINDOW, 0, pbuf);
  298.     tty_putstr(BASE_WINDOW, 0, "");
  299.     tty_display_nhwindow(BASE_WINDOW, TRUE);
  300.     getret();
  301.     }
  302. got_suffix:
  303.  
  304.     tty_clear_nhwindow(BASE_WINDOW);
  305.     pl_character[0] = pc;
  306.     return;
  307. }
  308.  
  309. /*
  310.  * plname is filled either by an option (-u Player  or  -uPlayer) or
  311.  * explicitly (by being the wizard) or by askname.
  312.  * It may still contain a suffix denoting pl_character.
  313.  * Always called after init_nhwindows() and before display_gamewindows().
  314.  */
  315. void
  316. tty_askname()
  317. {
  318.     register int c, ct;
  319.  
  320.     tty_putstr(BASE_WINDOW, 0, "");
  321.     tty_putstr(BASE_WINDOW, 0, "Who are you? ");
  322.     tty_curs(BASE_WINDOW, 14, wins[BASE_WINDOW]->cury-1);
  323.     ct = 0;
  324.     while((c = tty_nhgetch()) != '\n') {
  325.         if(c == EOF) error("End of input\n");
  326. #ifndef VMS
  327.         /* some people get confused when their erase char is not ^H */
  328.         if(c == '\b') {
  329.             if(ct) {
  330.                 ct--;
  331. # ifdef MICRO
  332.                 msmsg("\b \b");
  333. # else
  334.                 (void) putchar('\b');
  335.                 (void) putchar(' ');
  336.                 (void) putchar('\b');
  337. # endif
  338.             }
  339.             continue;
  340.         }
  341. #endif
  342. #if defined(UNIX) || defined(VMS)
  343.         if(c != '-')
  344.         if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
  345. #endif
  346.         if(ct < sizeof(plname)-1) {
  347. #if defined(MICRO)
  348.             msmsg("%c", c);
  349. #else
  350.             (void) putchar(c);
  351. #endif
  352.             plname[ct++] = c;
  353.         }
  354.     }
  355.     plname[ct] = 0;
  356.     tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury+1);
  357.     if(ct == 0) tty_askname();
  358. }
  359.  
  360. void
  361. tty_get_nh_event()
  362. {
  363. #ifdef LINT
  364.     /*
  365.      * We should do absolutely nothing here - but lint
  366.      * complains about that, so we call donull().
  367.      */
  368.      (void) donull();
  369. #endif
  370. }
  371.  
  372. #ifndef MICRO
  373. static void
  374. getret()
  375. {
  376.     xputs("\n");
  377.     if(flags.standout)
  378.         standoutbeg();
  379.     xputs("Hit ");
  380.     xputs(flags.cbreak ? "space" : "return");
  381.     xputs(" to continue: ");
  382.     if(flags.standout)
  383.         standoutend();
  384.     xwaitforspace("");
  385. }
  386. #endif
  387.  
  388. void
  389. tty_suspend_nhwindows(str)
  390.     const char *str;
  391. {
  392.     settty(str);        /* calls end_screen, perhaps raw_print */
  393.     if (!str) tty_raw_print("");    /* calls fflush(stdout) */
  394. }
  395.  
  396. void
  397. tty_resume_nhwindows()
  398. {
  399.     gettty();
  400.     setftty();            /* calls start_screen */
  401.     docrt();
  402. }
  403.  
  404. void
  405. tty_exit_nhwindows(str)
  406.     const char *str;
  407. {
  408.     winid i;
  409.  
  410.     tty_suspend_nhwindows(str);
  411.     /* Just forget any windows existed, since we're about to exit anyway.
  412.      * Disable windows to avoid calls to window routines.
  413.      */
  414.     for(i=0; i<MAXWIN; i++)
  415.     if(i != BASE_WINDOW)
  416.         wins[i] = 0;
  417.     flags.window_inited = 0;
  418. }
  419.  
  420. winid
  421. tty_create_nhwindow(type)
  422.     int type;
  423. {
  424.     struct WinDesc* newwin;
  425.     int i;
  426.     int newid;
  427.  
  428.     if(maxwin == MAXWIN)
  429.     return WIN_ERR;
  430.  
  431.     newwin = (struct WinDesc*) alloc(sizeof(struct WinDesc));
  432.     newwin->type = type;
  433.     newwin->flags = 0;
  434.     newwin->active = FALSE;
  435.     newwin->curx = newwin->cury = 0;
  436.     newwin->resp = newwin->canresp = newwin->morestr = 0;
  437.     switch(type) {
  438.     case NHW_BASE:
  439.     /* base window, used for absolute movement on the screen */
  440.     newwin->offx = newwin->offy = 0;
  441.     newwin->rows = ttyDisplay->rows;
  442.     newwin->cols = ttyDisplay->cols;
  443.     newwin->maxrow = newwin->maxcol = 0;
  444.     break;
  445.     case NHW_MESSAGE:
  446.     /* message window, 1 line long, very wide, top of screen */
  447.     newwin->offx = newwin->offy = 0;
  448.     /* sanity check */
  449.     if(flags.msg_history < 20) flags.msg_history = 20;
  450.     else if(flags.msg_history > 60) flags.msg_history = 60;
  451.     newwin->maxrow = newwin->rows = flags.msg_history;
  452.     newwin->maxcol = newwin->cols = 0;
  453.     break;
  454.     case NHW_STATUS:
  455.     /* status window, 2 lines long, full width, bottom of screen */
  456.     newwin->offx = 0;
  457.     newwin->offy = min((int)ttyDisplay->rows-2, ROWNO+1);
  458.     newwin->rows = newwin->maxrow = 2;
  459.     newwin->cols = newwin->maxcol = min(ttyDisplay->cols, COLNO);
  460.     break;
  461.     case NHW_MAP:
  462.     /* map window, ROWNO lines long, full width, below message window */
  463.     newwin->offx = 0;
  464.     newwin->offy = 1;
  465.     newwin->rows = ROWNO;
  466.     newwin->cols = COLNO;
  467.     newwin->maxrow = 0;    /* no buffering done -- let gbuf do it */
  468.     newwin->maxcol = 0;
  469.     break;
  470.     case NHW_MENU:
  471.     newwin->resp = (char*) alloc(256);
  472.     newwin->resp[0] = 0;
  473.     case NHW_TEXT:
  474.     /* inventory/menu window, variable length, full width, top of screen */
  475.     /* help window, the same, different semantics for display, etc */
  476.     newwin->offx = newwin->offy = 0;
  477.     newwin->rows = 0;
  478.     newwin->cols = ttyDisplay->cols;
  479.     newwin->maxrow = newwin->maxcol = 0;
  480.     break;
  481.    default:
  482.     panic("Tried to create window type %d\n", (int) type);
  483.     return WIN_ERR;
  484.     }
  485.  
  486.     for(newid = 0; newid<MAXWIN; newid++) {
  487.     if(wins[newid] == 0) {
  488.         wins[newid] = newwin;
  489.         break;
  490.     }
  491.     }
  492.     if(newid == MAXWIN) {
  493.     panic("No window slots!");
  494.     return WIN_ERR;
  495.     }
  496.  
  497.     if(newwin->maxrow) {
  498.     newwin->data = (char**) alloc(sizeof(char**) * newwin->maxrow);
  499.     if(newwin->maxcol) {
  500.         for(i=0; i< newwin->maxrow; i++)
  501.         newwin->data[i] = (char*)alloc(sizeof(char*) * newwin->maxcol);
  502.     } else {
  503.         for(i=0; i< newwin->maxrow; i++)
  504.         newwin->data[i] = 0;
  505.     }
  506.     if(newwin->type == NHW_MESSAGE)
  507.         newwin->maxrow = 0;
  508.     } else
  509.     newwin->data = 0;
  510.  
  511.     return newid;
  512. }
  513.  
  514. void
  515. tty_clear_nhwindow(window)
  516.     winid window;
  517. {
  518.     register struct WinDesc *cw = 0;
  519.     int i;
  520.  
  521.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  522.     panic(winpanicstr,  window);
  523.     ttyDisplay->lastwin = window;
  524.  
  525.     switch(cw->type) {
  526.     case NHW_MESSAGE:
  527.     if(ttyDisplay->toplin) {
  528.         home();
  529.         cl_end();
  530.         if(cw->cury)
  531.         docorner(1, cw->cury+1);
  532.         ttyDisplay->toplin = 0;
  533.     }
  534.     break;
  535.     case NHW_STATUS:
  536.     tty_curs(window, 1, 0);
  537.     cl_end();
  538.     tty_curs(window, 1, 1);
  539.     cl_end();
  540.     break;
  541.     case NHW_MAP:
  542.     /* cheap -- clear the whole thing and tell nethack to redraw botl */
  543.     flags.botlx = 1;
  544.     /* fall into ... */
  545.     case NHW_BASE:
  546.     clear_screen();
  547.     break;
  548.     case NHW_MENU:
  549.     case NHW_TEXT:
  550.     if(cw->active) {
  551.         if(cw->offx == 0)
  552.         if(cw->offy) {
  553.             tty_curs(window, 1, 0);
  554.             cl_eos();
  555.         } else
  556.             clear_screen();
  557.         else
  558.         docorner((int)cw->offx, cw->maxrow+1);
  559.     }
  560.     for(i=0; i<cw->maxrow; i++)
  561.         if(cw->data[i]) {
  562.         free((genericptr_t)cw->data[i]);
  563.         cw->data[i] = 0;
  564.         }
  565.     cw->maxrow = cw->maxcol = 0;
  566.     if(cw->resp)
  567.         cw->resp[0] = 0;
  568.     if(cw->canresp) {
  569.         free((genericptr_t)cw->canresp);
  570.         cw->canresp = 0;
  571.     }
  572.     if(cw->morestr) {
  573.         free((genericptr_t)cw->morestr);
  574.         cw->morestr = 0;
  575.     }
  576.     break;
  577.     }
  578.     cw->curx = cw->cury = 0;
  579. }
  580.  
  581. static void
  582. dmore(cw)
  583.     register struct WinDesc *cw;
  584. {
  585.     const char *s = (cw->resp && *cw->resp) ? cw->resp : quitchars;
  586.     const char *prompt = cw->morestr ? cw->morestr : defmorestr;
  587.     if(cw->type == NHW_TEXT)
  588.     tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury);
  589.     else
  590.     tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+2, (int)ttyDisplay->cury);
  591.     if(flags.standout)
  592.     standoutbeg();
  593.     xputs(prompt);
  594.     ttyDisplay->curx += strlen(prompt);
  595.     if(flags.standout)
  596.     standoutend();
  597.  
  598.     xwaitforspace(s);
  599. }
  600.  
  601. /*ARGSUSED*/
  602. void
  603. tty_display_nhwindow(window, blocking)
  604.     winid window;
  605.     boolean blocking;    /* with ttys, all windows are blocking */
  606. {
  607.     register struct WinDesc *cw = 0;
  608.     int i, n, attr;
  609.     register char *cp;
  610.  
  611.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  612.     panic(winpanicstr,  window);
  613.     if(cw->flags & WIN_CANCELLED)
  614.     return;
  615.     ttyDisplay->lastwin = window;
  616.     ttyDisplay->rawprint = 0;
  617.  
  618.     switch(cw->type) {
  619.     case NHW_MESSAGE:
  620.     if(ttyDisplay->toplin == 1) {
  621.         more();
  622.         ttyDisplay->toplin = 1; /* more resets this */
  623.         tty_clear_nhwindow(window);
  624.     } else
  625.         ttyDisplay->toplin = 0;
  626.     cw->curx = cw->cury = 0;
  627.     if(!cw->active)
  628.         flags.window_inited = TRUE;
  629.     break;
  630.     case NHW_MAP:
  631.     end_glyphout();
  632.     if(blocking) {
  633.         if(!ttyDisplay->toplin) ttyDisplay->toplin = 1;
  634.         tty_display_nhwindow(WIN_MESSAGE, TRUE);
  635.         return;
  636.     }
  637.     case NHW_BASE:
  638.     (void) fflush(stdout);
  639.     break;
  640.     case NHW_TEXT:
  641.     cw->maxcol = ttyDisplay->cols; /* force full-screen mode */
  642.     case NHW_MENU:
  643.     cw->active = 1;
  644.     /* avoid converting to uchar before calculations are finished */
  645.     cw->offx = (uchar) (int)
  646.         max((int) 10, (int) (ttyDisplay->cols - cw->maxcol - 1));
  647.     if(cw->type == NHW_MENU)
  648.         cw->offy = 0;
  649.     if(ttyDisplay->toplin == 1)
  650.         tty_display_nhwindow(WIN_MESSAGE, TRUE);
  651.     if(cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows) {
  652.         cw->offx = 0;
  653.         if(cw->offy) {
  654.         tty_curs(window, 1, 0);
  655.         cl_eos();
  656.         } else
  657.         clear_screen();
  658.         ttyDisplay->toplin = 0;
  659.     } else
  660.         tty_clear_nhwindow(WIN_MESSAGE);
  661.  
  662.     for(n=0, i=0; i<cw->maxrow; i++) {
  663.         if(!cw->offx && (n+cw->offy == ttyDisplay->rows-1)) {
  664.         tty_curs(window, 1, n);
  665.         cl_end();
  666.         dmore(cw);
  667.         if(morc) {
  668.             if(!cw->canresp && (morc == '\033'))
  669.             cw->flags |= WIN_CANCELLED;
  670.             else if(cw->canresp && index(&cw->canresp[1], morc)) {
  671.             morc = cw->canresp[0];
  672.             cw->flags |= WIN_CANCELLED;
  673.             }
  674.             break;
  675.         }
  676.         if(cw->offy) {
  677.             tty_curs(window, 1, 0);
  678.             cl_eos();
  679.         } else
  680.             clear_screen();
  681.         n = 0;
  682.         }
  683.         tty_curs(window, 1, n++);
  684.         if(cw->offx) cl_end();
  685.         if(cw->data[i]) {
  686.         attr = cw->data[i][0]-1;
  687.         if(cw->type == NHW_MENU) {
  688.             (void) putchar(' '); ++ttyDisplay->curx;
  689.         }
  690.         if(attr)
  691.             xputs(s_atr2str(attr));
  692.         for(cp = &cw->data[i][1];
  693.             *cp && (int)++ttyDisplay->curx < (int) ttyDisplay->cols; )
  694.             (void) putchar(*cp++);
  695.         if(attr)
  696.             xputs(e_atr2str(attr));
  697.         }
  698.     }
  699.     if(i == cw->maxrow) {
  700.         if(cw->type == NHW_TEXT)
  701.         tty_curs(BASE_WINDOW, (int)cw->offx+1, (int)ttyDisplay->rows-1);
  702.         else
  703.         tty_curs(BASE_WINDOW, (int)cw->offx+1, n);
  704.         cl_end();
  705.         dmore(cw);
  706.         if(morc) {
  707.         if(!cw->canresp && (morc == '\033'))
  708.             cw->flags |= WIN_CANCELLED;
  709.         else if(cw->canresp && index(&cw->canresp[1], morc)) {
  710.             morc = cw->canresp[0];
  711.             cw->flags |= WIN_CANCELLED;
  712.         }
  713.         }
  714.     }
  715.     break;
  716.     }
  717.     cw->active = 1;
  718. }
  719.  
  720. void
  721. tty_dismiss_nhwindow(window)
  722.     winid window;
  723. {
  724.     register struct WinDesc *cw = 0;
  725.  
  726.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  727.     panic(winpanicstr,  window);
  728.  
  729.     switch(cw->type) {
  730.     case NHW_STATUS:
  731.     case NHW_BASE:
  732.     case NHW_MESSAGE:
  733.     case NHW_MAP:
  734.     /*
  735.      * these should only get dismissed when the game is going away
  736.      * or suspending
  737.      */
  738.     tty_curs(BASE_WINDOW, 1, (int)ttyDisplay->rows-1);
  739.     cw->active = 0;
  740.     break;
  741.     case NHW_MENU:
  742.     case NHW_TEXT:
  743.     if(cw->active) {
  744.         if(cw->offx == 0) {
  745.         if(cw->offy) {
  746.             tty_curs(window, 1, 0);
  747.             cl_eos();
  748.         } else
  749.             docrt();
  750.         } else {
  751.         docorner((int)cw->offx, cw->maxrow+1);
  752.         }
  753.         cw->active = 0;
  754.     }
  755.     break;
  756.     }
  757.     cw->flags = 0;
  758. }
  759.  
  760. void
  761. tty_destroy_nhwindow(window)
  762.     winid window;
  763. {
  764.     register struct WinDesc *cw = 0;
  765.     int i;
  766.  
  767.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  768.     panic(winpanicstr,  window);
  769.  
  770.     if(cw->active)
  771.     tty_dismiss_nhwindow(window);
  772.     if(cw->type == NHW_MESSAGE)
  773.     flags.window_inited = 0;
  774.     if(cw->type == NHW_MAP)
  775.     clear_screen();
  776.  
  777.     if(cw->data) {
  778.     for(i=0; i<cw->rows; i++)
  779.         if(cw->data[i])
  780.         free((genericptr_t)cw->data[i]);
  781.     free((genericptr_t)cw->data);
  782.     }
  783.     if(cw->resp)
  784.     free((genericptr_t)cw->resp);
  785.     if(cw->canresp)
  786.     free((genericptr_t)cw->canresp);
  787.     free((genericptr_t)cw);
  788.     wins[window] = 0;
  789. }
  790.  
  791. void
  792. tty_curs(window, x, y)
  793. winid window;
  794. register int x, y;    /* not xchar: perhaps xchar is unsigned and
  795.                curx-x would be unsigned as well */
  796. {
  797.     struct WinDesc *cw = 0;
  798.     int cx = ttyDisplay->curx;
  799.     int cy = ttyDisplay->cury;
  800.  
  801.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  802.     panic(winpanicstr,  window);
  803.     ttyDisplay->lastwin = window;
  804.  
  805.     cw->curx = --x;    /* column 0 is never used */
  806.     cw->cury = y;
  807. #ifdef DEBUG
  808.     if(x<0 || y<0 || y >= cw->rows || x >= cw->cols) {
  809.     const char *s = "[unknown type]";
  810.     switch(cw->type) {
  811.     case NHW_MESSAGE: s = "[topl window]"; break;
  812.     case NHW_STATUS: s = "[status window]"; break;
  813.     case NHW_MAP: s = "[map window]"; break;
  814.     case NHW_MENU: s = "[corner window]"; break;
  815.     case NHW_TEXT: s = "[text window]"; break;
  816.     case NHW_BASE: s = "[base window]"; break;
  817.     }
  818.     impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y);
  819.     return;
  820.     }
  821. #endif
  822.     x += cw->offx;
  823.     y += cw->offy;
  824.  
  825. #ifdef CLIPPING
  826.     if(clipping && window == WIN_MAP) {
  827.     x -= clipx;
  828.     y -= clipy;
  829.     }
  830. #endif
  831.  
  832.     if (y == cy && x == cx)
  833.     return;
  834.  
  835.     if(cw->type == NHW_MAP)
  836.     end_glyphout();
  837.  
  838.     if(!ND && (cx != x || x <= 3)) { /* Extremely primitive */
  839.     cmov(x, y); /* bunker!wtm */
  840.     return;
  841.     }
  842.     if((cy -= y) < 0) cy = -cy;
  843.     if((cx -= x) < 0) cx = -cx;
  844.     if(cy <= 3 && cx <= 3)
  845.     nocmov(x, y);
  846.     else if((x <= 3 && cy <= 3) || (!CM && x < cx)) {
  847.     (void) putchar('\r');
  848.     ttyDisplay->curx = 0;
  849.     nocmov(x, y);
  850.     } else if(!CM) {
  851.     nocmov(x, y);
  852.     } else
  853.     cmov(x, y);
  854.  
  855.     ttyDisplay->curx = x;
  856.     ttyDisplay->cury = y;
  857. }
  858.  
  859. static void
  860. tty_putsym(window, x, y, ch)
  861.     winid window;
  862.     int x, y;
  863.     char ch;
  864. {
  865.     register struct WinDesc *cw = 0;
  866.  
  867.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  868.     panic(winpanicstr,  window);
  869.  
  870.     switch(cw->type) {
  871.     case NHW_STATUS:
  872.     case NHW_MAP:
  873.     case NHW_BASE:
  874.     tty_curs(window, x, y);
  875.     (void) putchar(ch);
  876.     ttyDisplay->curx++;
  877.     cw->curx++;
  878.     break;
  879.     case NHW_MESSAGE:
  880.     case NHW_MENU:
  881.     case NHW_TEXT:
  882.     impossible("Can't putsym to window type %d", cw->type);
  883.     break;
  884.     }
  885. }
  886.  
  887. static char nulstr[] = "";
  888.  
  889. static char *
  890. s_atr2str(n)
  891.     int n;
  892. {
  893.     switch(n) {
  894.     case ATR_ULINE:
  895.     if(US) return US;
  896.     case ATR_BOLD:
  897.     case ATR_BLINK:
  898.     case ATR_INVERSE:
  899.     return HI;
  900.     }
  901.     return nulstr;
  902. }
  903.  
  904. static char *
  905. e_atr2str(n)
  906.     int n;
  907. {
  908.     switch(n) {
  909.     case ATR_ULINE:
  910.     if(UE) return UE;
  911.     case ATR_BOLD:
  912.     case ATR_BLINK:
  913.     case ATR_INVERSE:
  914.     return HE;
  915.     }
  916.     return nulstr;
  917. }
  918.  
  919. static const char*
  920. compress_str(str)
  921. const char *str;
  922. {
  923.         static char cbuf[BUFSZ];
  924.     /* compress in case line too long */
  925.     if((int)strlen(str) >= CO) {
  926.         register const char *bp0 = str;
  927.         register char *bp1 = cbuf;
  928.  
  929.         do {
  930. #ifdef CLIPPING
  931.             if(*bp0 != ' ' || bp0[1] != ' ')
  932. #else
  933.             if(*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
  934. #endif
  935.                 *bp1++ = *bp0;
  936.         } while(*bp0++);
  937.     } else
  938.         return str;
  939.     return cbuf;
  940. }
  941.  
  942. void
  943. tty_putstr(window, attr, str)
  944.     winid window;
  945.     int attr;
  946.     const char *str;
  947. {
  948.     register struct WinDesc *cw = 0;
  949.     register char *ob;
  950.     register const char *nb;
  951.     register int i, j, n0;
  952.  
  953.     /* Assume there's a real problem if the window is missing --
  954.      * probably a panic message
  955.      */
  956.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) {
  957.     tty_raw_print(str);
  958.     return;
  959.     }
  960.  
  961.     if(str == (const char*)NULL || (cw->flags & WIN_CANCELLED))
  962.     return;
  963.     if(cw->type != NHW_MESSAGE)
  964.     str = compress_str(str);
  965.  
  966.     ttyDisplay->lastwin = window;
  967.  
  968.     switch(cw->type) {
  969.     case NHW_MESSAGE:
  970.     /* really do this later */
  971.     update_topl(str);
  972.     break;
  973.  
  974.     case NHW_STATUS:
  975.     ob = &cw->data[cw->cury][j = cw->curx];
  976.     if(flags.botlx) *ob = 0;
  977.     if(!cw->cury && (int)strlen(str) >= CO) {
  978.         /* the characters before "St:" are unnecessary */
  979.         nb = index(str, ':');
  980.         if(nb && nb > str+2)
  981.         str = nb - 2;
  982.     }
  983.     nb = str;
  984.     for(i = cw->curx+1, n0 = cw->cols; i < n0; i++, nb++) {
  985.         if(!*nb) {
  986.         if(*ob || flags.botlx) {
  987.             /* last char printed may be in middle of line */
  988.             tty_curs(WIN_STATUS, i, cw->cury);
  989.             cl_end();
  990.         }
  991.         break;
  992.         }
  993.         if(*ob != *nb)
  994.         tty_putsym(WIN_STATUS, i, cw->cury, *nb);
  995.         if(*ob) ob++;
  996.     }
  997.  
  998.     (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1);
  999.     cw->data[cw->cury][cw->cols-1] = '\0'; /* null terminate */
  1000.     cw->cury = (cw->cury+1) % 2;
  1001.     cw->curx = 0;
  1002.     break;
  1003.     case NHW_MAP:
  1004.     case NHW_BASE:
  1005.     tty_curs(window, cw->curx+1, cw->cury);
  1006.     if(attr)
  1007.         xputs(s_atr2str(attr));
  1008.     while(*str && (int) ttyDisplay->curx < (int) ttyDisplay->cols-1) {
  1009.         (void) putchar(*str++);
  1010.         ttyDisplay->curx++;
  1011.     }
  1012.     cw->curx = 0;
  1013.     cw->cury++;
  1014.     if(attr)
  1015.         xputs(e_atr2str(attr));
  1016.     break;
  1017.     case NHW_MENU:
  1018.     case NHW_TEXT:
  1019.     if(!(cw->resp && cw->resp[0]) && cw->cury == ttyDisplay->rows-1) {
  1020.         /* not a menu, so save memory and output 1 page at a time */
  1021.         cw->maxcol = ttyDisplay->cols; /* force full-screen mode */
  1022.         tty_display_nhwindow(window, TRUE);
  1023.         cw->maxrow = cw->cury = 0;
  1024.     }
  1025.     /* always grows one at a time, but alloc 12 at a time */
  1026.     if(cw->cury >= cw->rows) {
  1027.         char **tmp;
  1028.  
  1029.         cw->rows += 12;
  1030.         tmp = (char**) alloc(sizeof(char*) * cw->rows);
  1031.         for(i=0; i<cw->maxrow; i++)
  1032.         tmp[i] = cw->data[i];
  1033.         if(cw->data)
  1034.         free((genericptr_t)cw->data);
  1035.         cw->data = tmp;
  1036.  
  1037.         for(i=cw->maxrow; i<cw->rows; i++)
  1038.         cw->data[i] = 0;
  1039.     }
  1040.     if(cw->data[cw->cury])
  1041.         free((genericptr_t)cw->data[cw->cury]);
  1042.     n0 = strlen(str)+1;
  1043.     cw->data[cw->cury] = (char*) alloc(n0+1);
  1044.     cw->data[cw->cury][0] = attr+1;    /* avoid nuls, for convenience */
  1045.     Strcpy(&cw->data[cw->cury][1], str);
  1046.  
  1047.     if(n0 > cw->maxcol)
  1048.         cw->maxcol = n0;
  1049.     if(++cw->cury > cw->maxrow)
  1050.         cw->maxrow = cw->cury;
  1051.     if(n0 > CO) {
  1052.         /* attempt to break the line */
  1053.         for(i = CO-1; i && str[i] != ' ';)
  1054.         i--;
  1055.         if(i) {
  1056.         cw->data[cw->cury-1][++i] = '\0';
  1057.         tty_putstr(window, attr, &str[i]);
  1058.         }
  1059.         
  1060.     }
  1061.     break;
  1062.     }
  1063. }
  1064.  
  1065. void
  1066. tty_display_file(fname, complain)
  1067. const char *fname;
  1068. boolean complain;
  1069. {
  1070. #ifdef DEF_PAGER            /* this implies that UNIX is defined */
  1071.     {
  1072.     /* use external pager; this may give security problems */
  1073.     register int fd = open(fname, 0);
  1074.  
  1075.     if(fd < 0) {
  1076.         if(complain) pline("Cannot open %s.", fname);
  1077.         else docrt();
  1078.         return;
  1079.     }
  1080.     if(child(1)) {
  1081.         /* Now that child() does a setuid(getuid()) and a chdir(),
  1082.            we may not be able to open file fname anymore, so make
  1083.            it stdin. */
  1084.         (void) close(0);
  1085.         if(dup(fd)) {
  1086.         if(complain) raw_printf("Cannot open %s as stdin.", fname);
  1087.         } else {
  1088.         (void) execlp(catmore, "page", NULL);
  1089.         if(complain) raw_printf("Cannot exec %s.", catmore);
  1090.         }
  1091.         if(complain) sleep(10); /* want to wait_synch() but stdin is gone */
  1092.         terminate(1);
  1093.     }
  1094.     (void) close(fd);
  1095.     }
  1096. #else
  1097.     {
  1098.     FILE *f;
  1099.     char buf[BUFSZ];
  1100.     char *cr;
  1101.  
  1102.     tty_clear_nhwindow(WIN_MESSAGE);
  1103.     f = fopen_datafile(fname, "r");
  1104.     if (!f) {
  1105.         if(complain) {
  1106.         home();  tty_mark_synch();  tty_raw_print("");
  1107.         perror(fname);  tty_wait_synch();
  1108.         pline("Cannot open \"%s\".", fname);
  1109.         } else if(u.ux) docrt();
  1110.     } else {
  1111.         winid datawin = tty_create_nhwindow(NHW_TEXT);
  1112.         if(complain && CD) {
  1113.         /* attempt to scroll text below map window if there's room */
  1114.         wins[datawin]->offy = wins[WIN_STATUS]->offy+3;
  1115.         if((int) wins[datawin]->offy + 12 > (int) ttyDisplay->rows)
  1116.             wins[datawin]->offy = 0;
  1117.         }
  1118.         while (fgets(buf, BUFSZ, f)) {
  1119.         if ((cr = index(buf, '\n')) != 0) *cr = 0;
  1120.         if (index(buf, '\t') != 0) (void) tabexpand(buf);
  1121.         tty_putstr(datawin, 0, buf);
  1122.         if(wins[datawin]->flags & WIN_CANCELLED)
  1123.             break;
  1124.         }
  1125.         tty_display_nhwindow(datawin, FALSE);
  1126.         tty_destroy_nhwindow(datawin);
  1127.         (void) fclose(f);
  1128.     }
  1129.     }
  1130. #endif /* DEF_PAGER */
  1131. }
  1132.  
  1133. void
  1134. tty_start_menu(window)
  1135.     winid window;
  1136. {
  1137.     tty_clear_nhwindow(window);
  1138.     return;
  1139. }
  1140.  
  1141. /*
  1142.  * Add a menu item.  window must be an NHW_MENU type,
  1143.  * ch is the value to return if this entry is selected.
  1144.  * attr are attributes to set for this line (like tty_putstr())
  1145.  * str is the value to display on this menu line
  1146.  */
  1147. void
  1148. tty_add_menu(window, ch, attr, str)
  1149.     winid window;
  1150.     char ch;
  1151.     int attr;
  1152.     const char *str;
  1153. {
  1154.     register struct WinDesc *cw = 0;
  1155.     char tmpbuf[2];
  1156.  
  1157.     if(str == (const char*)NULL)
  1158.     return;
  1159.  
  1160.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0
  1161.        || cw->type != NHW_MENU)
  1162.     panic(winpanicstr,  window);
  1163.  
  1164.     tty_putstr(window, attr, str);
  1165.     if(ch != '\0') {
  1166.     tmpbuf[0] = ch;
  1167.     tmpbuf[1] = 0;
  1168.     Strcat(cw->resp, tmpbuf);
  1169.     }
  1170. }
  1171.  
  1172. /*
  1173.  * End a menu in this window, window must a type NHW_MENU.
  1174.  * ch is the value to return if the menu is canceled,
  1175.  * str is a list of cancel characters (values that may be input)
  1176.  * morestr is a prompt to display, rather than the default.
  1177.  * str and morestr might be ignored by some ports.
  1178.  */
  1179. void
  1180. tty_end_menu(window, ch, str, morestr)
  1181.     winid window;
  1182.     char ch;
  1183.     const char *str;
  1184.     const char *morestr;
  1185. {
  1186.     register struct WinDesc *cw = 0;
  1187.  
  1188.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 ||
  1189.        cw->type != NHW_MENU || cw->canresp)
  1190.     panic(winpanicstr,  window);
  1191.  
  1192.     if(str) {
  1193.     cw->canresp = (char*) alloc(strlen(str)+2);
  1194.     cw->canresp[0] = ch;            /* this could be NUL? */
  1195.     Strcpy(&cw->canresp[1], str);
  1196.     Strcat(cw->resp, str);
  1197.     }
  1198.     if(morestr) {
  1199.     unsigned int len = strlen(morestr) + 1;
  1200.     cw->morestr = (char*) alloc(len);
  1201.     Strcpy(cw->morestr, morestr);
  1202.     if(++len > cw->maxcol)    /* add one to avoid using the rtmost column */
  1203.         cw->maxcol = len;
  1204.     }
  1205. }
  1206.  
  1207. char
  1208. tty_select_menu(window)
  1209.     winid window;
  1210. {
  1211.     register struct WinDesc *cw = 0;
  1212.  
  1213.     morc = 0;
  1214.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0
  1215.        || cw->type != NHW_MENU)
  1216.     panic(winpanicstr,  window);
  1217.     tty_display_nhwindow(window, TRUE);
  1218.     tty_dismiss_nhwindow(window);
  1219.  
  1220.     return morc;
  1221. }
  1222.  
  1223. void
  1224. tty_update_inventory()
  1225. {
  1226. }
  1227.  
  1228. void
  1229. tty_mark_synch()
  1230. {
  1231.     (void) fflush(stdout);
  1232. }
  1233.  
  1234. void
  1235. tty_wait_synch()
  1236. {
  1237.     /* we just need to make sure all windows are synch'd */
  1238.     if(!ttyDisplay || ttyDisplay->rawprint) {
  1239.     getret();
  1240.     if(ttyDisplay) ttyDisplay->rawprint = 0;
  1241.     } else {
  1242.     tty_display_nhwindow(WIN_MAP, FALSE);
  1243.     if(ttyDisplay->inmore) {
  1244.         addtopl("--More--");
  1245.         (void) fflush(stdout);
  1246.     } else if(ttyDisplay->inread) {
  1247.         ttyDisplay->toplin = 3;
  1248.         /* do this twice; 1st time gets the Quit? message again */
  1249.         (void) tty_doprev_message();
  1250.         (void) tty_doprev_message();
  1251.         (void) fflush(stdout);
  1252.     }
  1253.     }
  1254. }
  1255.  
  1256. void
  1257. docorner(xmin, ymax)
  1258.     register int xmin, ymax;
  1259. {
  1260.     register int y;
  1261.     register struct WinDesc *cw = wins[WIN_MAP];
  1262.  
  1263.     if (u.uswallow) {    /* Can be done more efficiently */
  1264.     swallowed(1);
  1265.     return;
  1266.     }
  1267.  
  1268. #if defined(SIGWINCH) && defined(CLIPPING)
  1269.     if(ymax > LI) ymax = LI;        /* can happen if window gets smaller */
  1270. #endif
  1271.     for (y = 0; y < ymax; y++) {
  1272.     tty_curs(BASE_WINDOW, xmin,y);    /* move cursor */
  1273.     cl_end();            /* clear to end of line */
  1274. #ifdef CLIPPING
  1275.     if (y<(int) cw->offy || y+clipy > ROWNO) 
  1276.         continue; /* only refresh board */
  1277.     row_refresh(xmin+clipx-(int)cw->offx,COLNO-1,y+clipy-(int)cw->offy);
  1278. #else
  1279.     if (y<cw->offy || y > ROWNO) continue; /* only refresh board  */
  1280.     row_refresh(xmin-(int)cw->offx,COLNO-1,y-(int)cw->offy);
  1281. #endif
  1282.     }
  1283.  
  1284.     end_glyphout();
  1285.     if (ymax >= (int) wins[WIN_STATUS]->offy) { 
  1286.                     /* we have wrecked the bottom line */
  1287.     flags.botlx = 1;
  1288.     bot();
  1289.     }
  1290. }
  1291.  
  1292. void
  1293. end_glyphout()
  1294. {
  1295. #ifdef ASCIIGRAPH
  1296.     if (GFlag) {
  1297.     GFlag = FALSE;
  1298.     graph_off();
  1299.     }
  1300. #endif
  1301. #ifdef TEXTCOLOR
  1302.     if(ttyDisplay->color != NO_COLOR) {
  1303.     xputs(HE);
  1304.     ttyDisplay->color = NO_COLOR;
  1305.     }
  1306. #endif
  1307. }
  1308.  
  1309. #ifdef ASCIIGRAPH
  1310. void
  1311. g_putch(ch)
  1312.     uchar ch;
  1313. {
  1314.     if (flags.IBMgraphics)
  1315.     /* IBM-compatible displays don't need other stuff */
  1316.     (void) putchar((char) ch);
  1317.     else if (ch & 0x80) {
  1318.     if (!GFlag) {
  1319.         graph_on();
  1320.         GFlag = TRUE;
  1321.     }
  1322.     (void) putchar((char) (ch ^ 0x80)); /* Strip 8th bit */
  1323.     } else {
  1324.     if (GFlag) {
  1325.         graph_off();
  1326.         GFlag = FALSE;
  1327.     }
  1328.     (void) putchar((char) ch);
  1329.     }
  1330. }
  1331.  
  1332. #else
  1333.  
  1334. void
  1335. g_putch(ch)
  1336.     uchar ch;
  1337. {
  1338.     (void) putchar((char)(ch));
  1339. };
  1340.  
  1341. #endif    /* ASCIIGRAPH */
  1342.  
  1343. #ifdef CLIPPING
  1344. void
  1345. setclipped()
  1346. {
  1347.     clipping = TRUE;
  1348.     clipx = clipy = 0;
  1349.     clipxmax = CO;
  1350.     clipymax = LI - 3;
  1351. }
  1352.  
  1353. void
  1354. tty_cliparound(x, y)
  1355. int x, y;
  1356. {
  1357.     int oldx = clipx, oldy = clipy;
  1358.  
  1359.     if (!clipping) return;
  1360.     if (x < clipx + 5) {
  1361.         clipx = max(0, x - 20);
  1362.         clipxmax = clipx + CO;
  1363.     }
  1364.     else if (x > clipxmax - 5) {
  1365.         clipxmax = min(COLNO, clipxmax + 20);
  1366.         clipx = clipxmax - CO;
  1367.     }
  1368.     if (y < clipy + 2) {
  1369.         clipy = max(0, y - (clipymax - clipy) / 2);
  1370.         clipymax = clipy + (LI - 3);
  1371.     }
  1372.     else if (y > clipymax - 2) {
  1373.         clipymax = min(ROWNO, clipymax + (clipymax - clipy) / 2);
  1374.         clipy = clipymax - (LI - 3);
  1375.     }
  1376.     if (clipx != oldx || clipy != oldy) {
  1377.         (void) doredraw();
  1378.     }
  1379. }
  1380. #endif /* CLIPPING */
  1381.  
  1382.  
  1383. /*
  1384.  *  tty_print_glyph
  1385.  *
  1386.  *  Print the glyph to the output device.  Don't flush the output device.
  1387.  *
  1388.  *  Since this is only called from show_glyph(), it is assumed that the
  1389.  *  position and glyph are always correct (checked there)!
  1390.  */
  1391. void
  1392. tty_print_glyph(window, x, y, glyph)
  1393.     winid window;
  1394.     xchar x, y;
  1395.     int glyph;
  1396. {
  1397.     uchar   ch;
  1398.     register int offset;
  1399. #ifdef TEXTCOLOR
  1400.     int        color;
  1401.  
  1402. #define zap_color(n)  color = flags.use_color ? zapcolors[n] : NO_COLOR
  1403. #define cmap_color(n) color = flags.use_color ? defsyms[n].color : NO_COLOR
  1404. #define trap_color(n) color = flags.use_color ? \
  1405.                 (((n) == WEB) ? defsyms[S_web ].color  : \
  1406.                             defsyms[S_trap].color) : \
  1407.                         NO_COLOR
  1408. #define obj_color(n)  color = flags.use_color ? objects[n].oc_color : NO_COLOR
  1409. #define mon_color(n)  color = flags.use_color ? mons[n].mcolor : NO_COLOR
  1410. #define pet_color(n)  color = flags.use_color ? mons[n].mcolor :          \
  1411.                 /* If no color, try to hilite pets; black  */ \
  1412.                 /* should be HI                   */ \
  1413.                     ((flags.hilite_pet && hilites[BLACK]) ?          \
  1414.                             BLACK : NO_COLOR)
  1415. # else /* no text color */
  1416.  
  1417. #define zap_color(n)
  1418. #define cmap_color(n)
  1419. #define trap_color(n)
  1420. #define obj_color(n)
  1421. #define mon_color(n)
  1422. #define pet_color(c)
  1423. #endif
  1424.  
  1425. #ifdef CLIPPING
  1426.     if(clipping) {
  1427.     if(x <= clipx || y < clipy || x >= clipxmax || y >= clipymax)
  1428.         return;
  1429.     }
  1430. #endif
  1431.     /*
  1432.      *  Map the glyph back to a character.
  1433.      *
  1434.      *  Warning:  For speed, this makes an assumption on the order of
  1435.      *          offsets.  The order is set in display.h.
  1436.      */
  1437.     if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) {        /* swallow */
  1438.     /* see swallow_to_glyph() in display.c */
  1439.     ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
  1440.     mon_color(offset >> 3);
  1441.     } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) {    /* zap beam */
  1442.     /* see zapdir_to_glyph() in display.c */
  1443.     ch = showsyms[S_vbeam + (offset & 0x3)];
  1444.     zap_color((offset >> 2));
  1445.     } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) {    /* cmap */
  1446.     ch = showsyms[offset];
  1447.     cmap_color(offset);
  1448.     } else if ((offset = (glyph - GLYPH_TRAP_OFF)) >= 0) {    /* trap */
  1449.     ch = (offset == WEB) ? showsyms[S_web] : showsyms[S_trap];
  1450.     trap_color(offset);
  1451.     } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) {    /* object */
  1452.     ch = oc_syms[objects[offset].oc_class];
  1453.     obj_color(offset);
  1454.     } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) {    /* a corpse */
  1455.     ch = oc_syms[objects[CORPSE].oc_class];
  1456.     mon_color(offset);
  1457.     } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) {    /* a pet */
  1458.     ch = monsyms[mons[offset].mlet];
  1459.     pet_color(offset);
  1460.     } else {                            /* a monster */
  1461.     ch = monsyms[mons[glyph].mlet];
  1462.     mon_color(glyph);
  1463.     }
  1464.  
  1465.     /* Move the cursor. */
  1466.     tty_curs(window, x,y);
  1467.  
  1468.     if (ul_hack && ch == '_') {        /* non-destructive underscore */
  1469.     (void) putchar((char) ' ');
  1470.     backsp();
  1471.     }
  1472.  
  1473. #ifdef TEXTCOLOR
  1474.     /* Turn off color if no color defined, or rogue level. */
  1475. #  ifdef REINCARNATION
  1476.     if (hilites[color] == NULL || Is_rogue_level(&u.uz))
  1477. #  else
  1478.     if (hilites[color] == NULL)
  1479. #  endif
  1480.     color = NO_COLOR;
  1481.  
  1482.     if (color != ttyDisplay->color) {
  1483.     if(ttyDisplay->color != NO_COLOR)
  1484.         xputs(HE);
  1485.     ttyDisplay->color = color;
  1486.     if(color != NO_COLOR)
  1487.         xputs(hilites[color]);
  1488.     }
  1489. #endif
  1490.     g_putch(ch);        /* print the character */
  1491.     wins[window]->curx++;    /* one character over */
  1492.     ttyDisplay->curx++;        /* the real cursor moved too */
  1493. }
  1494.  
  1495. void
  1496. tty_raw_print(str)
  1497.     const char *str;
  1498. {
  1499.     if(ttyDisplay) ttyDisplay->rawprint++;
  1500. #ifdef MICRO
  1501.     msmsg("%s\n", str);
  1502. #else
  1503.     puts(str); (void) fflush(stdout);
  1504. #endif
  1505. }
  1506.  
  1507. void
  1508. tty_raw_print_bold(str)
  1509.     const char *str;
  1510. {
  1511.     if(ttyDisplay) ttyDisplay->rawprint++;
  1512.     xputs(HI);
  1513. #ifdef MICRO
  1514.     msmsg("%s", str);
  1515. #else
  1516.     (void) fputs(str, stdout);
  1517. #endif
  1518.     xputs(HE);
  1519. #ifdef MICRO
  1520.     msmsg("\n");
  1521. #else
  1522.     puts("");
  1523.     (void) fflush(stdout);
  1524. #endif
  1525. }
  1526.  
  1527. int
  1528. tty_nhgetch()
  1529. {
  1530.     int i;
  1531. #ifdef UNIX
  1532.     /* kludge alert: Some Unix variants return funny values if getc()
  1533.      * is called, interrupted, and then called again.  There
  1534.      * is non-reentrant code in the internal _filbuf() routine, called by
  1535.      * getc().
  1536.      */
  1537.     static volatile int nesting = 0;
  1538.     char nestbuf;
  1539. #endif
  1540.  
  1541.     (void) fflush(stdout);
  1542.     /* Note: if raw_print() and wait_synch() get called to report terminal
  1543.      * initialization problems, then wins[] and ttyDisplay might not be
  1544.      * available yet.  Such problems will probably be fatal before we get
  1545.      * here, but validate those pointers just in case...
  1546.      */
  1547.     if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
  1548.         wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
  1549. #ifdef UNIX
  1550.     i = ((++nesting == 1) ? tgetch() :
  1551.      (read(fileno(stdin), (genericptr_t)&nestbuf,1) == 1 ? (int)nestbuf :
  1552.                                 EOF));
  1553.     --nesting;
  1554. #else
  1555.     i = tgetch();
  1556. #endif
  1557.     if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
  1558.     if (ttyDisplay && ttyDisplay->toplin == 1)
  1559.     ttyDisplay->toplin = 2;
  1560.     return i;
  1561. }
  1562.  
  1563. /*
  1564.  * return a key, or 0, in which case a mouse button was pressed
  1565.  * mouse events should be returned as character postitions in the map window.
  1566.  * Since normal tty's don't have mice, just return a key.
  1567.  */
  1568. /*ARGSUSED*/
  1569. int
  1570. tty_nh_poskey(x, y, mod)
  1571.     int *x, *y, *mod;
  1572. {
  1573.     return tty_nhgetch();
  1574. }
  1575.  
  1576. void
  1577. win_tty_init()
  1578. {
  1579.     return;
  1580. }
  1581.  
  1582. /*wintty.c*/
  1583.